package com.antstorm.statistics.service.onlineOffline;

import com.alibaba.fastjson.JSONObject;
import com.antstorm.statistics.dao.DeviceOnlineStatusRecordDao;
import com.antstorm.statistics.dao.OnlineDurationTimeStreamDao;
import com.antstorm.statistics.entity.DeviceOnlineStatusRecord;
import com.antstorm.statistics.pojo.DeviceOfflineJson;
import com.antstorm.statistics.pojo.OwnJsonDemo;
import com.antstorm.statistics.service.mqtt.MqttMsgHandlerAbs;
import com.antstorm.statistics.util.DateTimeUtil;
import com.antstorm.statistics.util.FastJsonUtil;
import com.antstorm.statistics.util.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.time.LocalDate;
import java.time.Period;
import java.util.Date;
import java.util.Map;

/**
 * 设备上下线的mq消息的处理器
 */
@Service
public class MqttMsgHandlerOfDeviceOffline extends MqttMsgHandlerAbs {

    private static Logger logger = LoggerFactory.getLogger(MqttMsgHandlerOfDeviceOffline.class);

    @Autowired
    private OnlineDurationTimeStreamDao onlineDurationTimeStreamDao;

    @Autowired
    private DeviceOnlineStatusRecordDao deviceOnlineStatusRecordDao;

    @PostConstruct
    @Override
    public void initTopic() {
        // 设备上下线的topic
        this.topic = "GID_ant_storm_device_debug_MQTT";
    }


    /**
     * 解析设备上线下线消息
     *
     * @param mqttMessage
     */
    @Override
    public void handle(MqttMessage mqttMessage) {
        String message = new String(mqttMessage.getPayload());
        logger.info("接收到 <设备mq消息> : " + message);

        // 上下线json格式
        DeviceOfflineJson deviceOfflineJson = null;

        //  todo: 业务json格式
        Object jsonObject = parseMqMsg(message);

        if (jsonObject == null) {
            return;
        }

        if (jsonObject instanceof DeviceOfflineJson) {
            processOffline((DeviceOfflineJson) jsonObject);
        }else{
            processWork((OwnJsonDemo) jsonObject);
        }


    }


    /**
     * 处理上下线
     */
    private void processOffline(DeviceOfflineJson json) {
        if (!StringUtils.endsWithIgnoreCase(json.getClientId(), "server")) {
            String uuid = StringUtils.substringAfter(json.getClientId(), "@@@");

            if (StringUtils.equalsIgnoreCase("connect", json.getEventType())) {
                //客户端上线
                processDeviceOnline(json.getChannelId(), uuid, json.getTime());
            } else if (StringUtils.equalsIgnoreCase("tcpclean", json.getEventType())) {
                // 处理设备下线
                processDeviceOffline(json.getChannelId(), uuid, json.getTime());

            }
        }
    }


    /**
     * 处理业务
     */
    private void processWork(OwnJsonDemo ownJson) {
        // todo: 需要处理的业务内容待定

    }


    /**
     * @param msg mq的消息内容  ,如果mq的格式内容不符合指定的格式，那么返回 null
     * @return
     */
    private Object parseMqMsg(String msg) {
        Object result = null;
        try {
            result = JSONObject.parseObject(msg, DeviceOfflineJson.class);
        } catch (Exception e) {
            // 转换为 DeviceOfflineJson 类型失败，则转换为 OwnJsonDemo

        }
        try {
            result = JSONObject.parseObject(msg, OwnJsonDemo.class);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(" <解析mq格式异常! >  msg:[{}] ", msg);
        }
        return result;
    }


    /**
     * 处理设备上线
     *
     * @param channelId mq消息的channelId
     * @param deviceId  设备id
     * @param time      事件发生的时间
     */
    public void processDeviceOnline(String channelId, String deviceId, Long time) {
        logger.info(" <设备上线 -- 开始> deviceId:[{}] ", deviceId);
        DeviceOnlineStatusRecord record = deviceOnlineStatusRecordDao.findByDeviceId(deviceId);
        if (record == null) {
            deviceOnlineStatusRecordDao.save(new DeviceOnlineStatusRecord(deviceId, new Date(time), true));
        } else if (record.isOnlineStatus()) {
            logger.error(" <设备状态已经为'online'，开始强制重新上线!> deviceId:[{}] , 设备原上线数据:[{}]", deviceId, record);
            record.setDate(new Date());
            deviceOnlineStatusRecordDao.save(record);
        } else {

            record.setDate(new Date());
            record.setOnlineStatus(true);
            deviceOnlineStatusRecordDao.save(record);
        }
        logger.info(" <设备上线 -- 完成> deviceId:[{}] ", deviceId);
    }

    /**
     * 处理设备下线
     *
     * @param channelId
     * @param deviceId  设备id
     * @param time
     */
    public void processDeviceOffline(String channelId, String deviceId, Long time) {
        try {
            logger.info("<设备下线开始！> deviceId:[{}] ,time:[{}] ,channelId:[{}]", deviceId, time, channelId);
            //1. 查询上线记录
            DeviceOnlineStatusRecord onlineRecord = getDeviceOnlineRecord(deviceId);

            if (onlineRecord == null) {
                processOfRecordIsNull(deviceId);
            } else {
                processOfRecordNotNull(onlineRecord, new Date(time));
            }
            logger.info("<设备下线完成！> deviceId:[{}] ,time:[{}] ,channelId:[{}]", deviceId, time, channelId);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("<处理下线数据发生异常！>  deviceId:[{}] ,channelId:[{}] ,time:[{}]", deviceId, channelId, time);
        }

    }

    /**
     * 处理设备上线记录不会空的流程
     *
     * @param onlineRecord
     * @param
     */
    private void processOfRecordNotNull(DeviceOnlineStatusRecord onlineRecord, Date offlineTime) {
        // 下线日期
        LocalDate offlineDate = DateTimeUtil.getLocalDate(offlineTime);

        // 上线日期
        LocalDate onlineDate = DateTimeUtil.getLocalDate(onlineRecord.getDate());

        // 上线日期临时
        Date tmpOnlineTime = onlineRecord.getDate();

        // 下线日期临时
        Date tmpOfflineTime = offlineTime;

        // 1. 获取上下线时间相隔的天数
        Period value = Period.between(onlineDate, offlineDate);

        if (value.getDays() == 0) {
            long duration = tmpOfflineTime.getTime() - tmpOnlineTime.getTime();
            onlineDurationTimeStreamDao.insertIntoStream(onlineRecord.getDeviceId(), duration,
                    DateTimeUtil.getLocalDate(tmpOfflineTime).toString());

        } else {
            // 计算间隔中的每日的上线时长
            for (int i = 0; i < value.getDays(); i++) {
                LocalDate tmpDate = DateTimeUtil.getLocalDate(tmpOnlineTime);
                tmpOfflineTime = i == value.getDays() ? offlineTime : DateTimeUtil.toDate(tmpDate.plusDays(1L));
                long duration = tmpOfflineTime.getTime() - tmpOnlineTime.getTime();
                onlineDurationTimeStreamDao.insertIntoStream(onlineRecord.getDeviceId(), duration, tmpDate.toString());
                tmpOnlineTime = tmpOfflineTime;
            }
        }

        // 2. 设置设备下线
        onlineRecord.setOnlineStatus(false);
        onlineRecord.setDate(offlineTime);
        deviceOnlineStatusRecordDao.save(onlineRecord);
    }

    /**
     * 处理设备上线记录为null流程
     *
     * @param deviceId
     */
    private void processOfRecordIsNull(String deviceId) {
        // todo:上线时间点丢失的情况，那么下线记录不纳入统计范围,后期如果确定了业务方案，再继续处理
    }


    /**
     * 查询该设备的有效上线记录
     *
     * @param deviceId
     * @return
     */
    private DeviceOnlineStatusRecord getDeviceOnlineRecord(String deviceId) {
        return deviceOnlineStatusRecordDao.findByDeviceIdAndOnlineStatus(deviceId, true);
    }


}
